package com.star.oauth2.client.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.Base64;
import java.util.Map;

/**
 * Token服务
 * 
 * 处理OAuth2 token相关操作
 * 
 * @author star
 */
@Slf4j
@Service
public class TokenService {

    @Value("${spring.security.oauth2.client.registration.oauth2-client.client-id}")
    private String clientId;

    @Value("${spring.security.oauth2.client.registration.oauth2-client.client-secret}")
    private String clientSecret;

    @Value("${spring.security.oauth2.client.provider.oauth2-client.token-uri}")
    private String tokenUri;

    private final RestTemplate restTemplate = new RestTemplate();

    /**
     * 使用授权码获取访问令牌
     * 
     * @param code 授权码
     * @param redirectUri 回调地址
     * @return 令牌响应
     */
    public Map<String, Object> getTokenByCode(String code, String redirectUri) {
        try {
            // 1. 准备请求头（使用Basic认证）
            String auth = clientId + ":" + clientSecret;
            String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            headers.set("Authorization", "Basic " + encodedAuth);

            // 2. 准备请求体
            MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
            body.add("grant_type", "authorization_code");
            body.add("code", code);
            body.add("redirect_uri", redirectUri);

            // 3. 发送请求到令牌端点
            HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
            
            log.info("正在向令牌端点发送请求: {}", tokenUri);
            ResponseEntity<Map> response = restTemplate.exchange(
                    tokenUri,
                    HttpMethod.POST,
                    request,
                    Map.class
            );
            
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                return response.getBody();
            } else {
                throw new RuntimeException("令牌端点返回异常状态: " + response.getStatusCode());
            }
        } catch (Exception e) {
            log.error("获取令牌失败", e);
            throw new RuntimeException("获取令牌失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 刷新访问令牌
     * 
     * @param refreshToken 刷新令牌
     * @return 新的令牌响应
     */
    public Map<String, Object> refreshToken(String refreshToken) {
        try {
            // 1. 准备请求头（使用Basic认证）
            String auth = clientId + ":" + clientSecret;
            String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes());
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            headers.set("Authorization", "Basic " + encodedAuth);

            // 2. 准备请求体
            MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
            body.add("grant_type", "refresh_token");
            body.add("refresh_token", refreshToken);

            // 3. 发送请求到令牌端点
            HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
            
            log.info("正在向令牌端点发送刷新令牌请求: {}", tokenUri);
            ResponseEntity<Map> response = restTemplate.exchange(
                    tokenUri,
                    HttpMethod.POST,
                    request,
                    Map.class
            );
            
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                return response.getBody();
            } else {
                throw new RuntimeException("令牌端点返回异常状态: " + response.getStatusCode());
            }
        } catch (Exception e) {
            log.error("刷新令牌失败", e);
            throw new RuntimeException("刷新令牌失败: " + e.getMessage(), e);
        }
    }
}
